#include "stdafx.h"

#include "parser_internal.h"
#include "parser_state.h"
#include "parser_errors.h"

#include "ast_expressions.h"
#include "ast_literals.h"

namespace funpl
{

namespace parser
{

ast::operator_id::t unary_operator(token_type::t type)
{
	using namespace token_type;
	using namespace ast::operator_id;

	switch (type)
	{
	case op_mul: return dereference;
	case op_and: return address;
	case op_tilde: return move;

	case op_add: return plus;
	case op_sub: return minus;
	case op_not: return not;
	
	case op_increment: return pre_increment;
	case op_decrement: return pre_decrement;
	
	default: return none;
	}
}

ast::operator_id::t postfix_operator(token_type::t type)
{
	using namespace token_type;
	using namespace ast::operator_id;

	switch (type)
	{
	case tok_oparen: return evaluate;
	case tok_obracket: return index;

	case op_increment: return post_increment;
	case op_decrement: return post_decrement;

	case op_to: return cast;
	case op_on: return on;
	
	default: return none;
	}
}

ast::operator_id::t binary_operator(token_type::t type)
{
	using namespace token_type;
	using namespace ast::operator_id;

	switch (type)
	{
	case tok_op_colon: return member;
	case op_period: return member_overload;
	
	case op_mul: return mul;
	case op_div: return div;
	case op_mod: return mod;

	case op_add: return add;
	case op_sub: return sub;

	case op_less: return less;
	case op_less_equal: return less_equal;
	case op_greater: return greater;
	case op_greater_equal: return greater_equal;

	case op_equal: return equal;
	case op_not_equal: return not_equal;

	case op_and: return and;
	case op_xor: return xor;
	case op_or: return or;
	
	case op_logical_and: return logical_and;
	case op_logical_or: return logical_or;
	
	case op_assign: return assign;

	case op_add_assign: return add_assign;
	case op_sub_assign: return sub_assign;
	case op_mul_assign: return mul_assign;
	case op_div_assign: return div_assign;
	case op_mod_assign: return mod_assign;
	
	case op_and_assign: return and_assign;
	case op_xor_assign: return xor_assign;
	case op_or_assign: return or_assign;

	default: return none;
	}
}

bool is_operator(token_type::t type)
{
	return (binary_operator(type) != ast::operator_id::none) &&
		(unary_operator(type) != ast::operator_id::none) &&
		(postfix_operator(type) != ast::operator_id::none);
}

/// Parses a lambda function.
ast::function_expression* parse_lambda_function(parser_state &state, ast::node *parent, bool implicitSemicolon)
{
	auto lambda = state.tree->create_node<ast::function_expression>(parent);

	// Lambda function
	lambda->function = parse_function(state, parent, true, implicitSemicolon);

	return lambda;
}

/// Parses an identifier.
ast::identifier* parse_identifier(parser_state &state, ast::node *parent)
{
	auto identifier = state.tree->create_node<ast::identifier>(parent);

	// Name
	identifier->name = expect_cont(state, token_type::tok_identifier).token.range;

	return identifier;
}

/// Parses a list of function arguments.
ast::arguments* parse_function_arguments(parser_state &state, ast::node *parent)
{
	expect_cont(state, token_type::tok_oparen);

	auto args = state.tree->create_node<ast::arguments>(parent);

	// Allow for empty argument list
	if (!check_cont(state, token_type::tok_cparen))
		do
		{
			// Argument
			args->args.push_back( parse_expression(state, args, false) );
		}
		while (accept_cont(state, token_type::tok_comma));

	expect_cont(state, token_type::tok_cparen);

	return args;
}

/// Parses a list of function arguments.
ast::evaluate* parse_function_evaluation(parser_state &state, ast::node *parent, ast::expression *expression)
{
	auto evaluate = state.tree->create_node<ast::evaluate>(parent);

	// Arguments
	evaluate->args = parse_function_arguments(state, evaluate);

	// Expression
	evaluate->operand = reparent(expression, evaluate);

	return evaluate;
}

/// Parses an array subscript.
ast::binary_operator* parse_array_subscript(parser_state &state, ast::node *parent, ast::expression *expression)
{
	expect_cont(state, token_type::tok_obracket);

	// Subscript operator
	auto operator_ = state.tree->create_node<ast::binary_operator>(parent);
	operator_->id = ast::operator_id::index;

	// Index
	operator_->right = parse_expression(state, operator_, false);

	expect_cont(state, token_type::tok_cbracket);

	// Expression
	operator_->left = expression;
	expression->parent = operator_;

	return operator_;
}

/// Parses a type cast.
ast::type_cast* parse_type_cast(parser_state &state, ast::node *parent, ast::expression *expression, bool implicitSemicolon)
{
	expect_cont(state, token_type::op_to);

	// Subscript operator
	auto cast = state.tree->create_node<ast::type_cast>(parent);

	// Type
	cast->to = parse_type(state, cast, implicitSemicolon);

	// Expression
	cast->operand = expression;
	expression->parent = cast;

	return cast;
}

/// Parses template expression arguments.
ast::metaevaluate* parse_metaarguments(parser_state &state, ast::node *parent, ast::expression *expression, bool implicitSemicolon)
{
	expect_cont(state, token_type::op_on);

	auto args = state.tree->create_node<ast::metaevaluate>(parent);

	// Arguments
	args->arguments = parse_metaarguments(state, args, implicitSemicolon);

	// Expression
	args->operand = expression;
	expression->parent = args;

	return args;
}

/// Parses a postfix operator.
ast::expression* maybe_parse_postfix_operator(parser_state &state, ast::node *parent, ast::expression *expression, int minPrecedence, bool implicitSemicolon)
{
	// Postfix operator
	ast::operator_id::t id = postfix_operator(next_token(state, implicitSemicolon).token.type);

	if (id == ast::operator_id::none)
		return expression;

	// Precendence >= minimum precedence
	ast::operator_desc operatorDesc = ast::operator_info(id);

	if (operatorDesc.precedence < minPrecedence)
		return expression;

	// Function call
	if (id == ast::operator_id::evaluate)
		expression = parse_function_evaluation(state, parent, expression);
	// Array subscript
	else if (id == ast::operator_id::index)
		expression = parse_array_subscript(state, parent, expression);
	// Type cast
	else if (id == ast::operator_id::cast)
		expression = parse_type_cast(state, parent, expression, implicitSemicolon);
	// Template arguments
	else if (id == ast::operator_id::on)
		expression = parse_metaarguments(state, parent, expression, implicitSemicolon);
	// Ordenary postfix
	else
	{
		// Operator
		auto operator_ = state.tree->create_node<ast::unary_operator>(parent);
		operator_->id = id;
		
		// Operand
		operator_->operand = expression;
		expression->parent = operator_;

		expression = operator_;
	}

	return maybe_parse_postfix_operator(state, parent, expression, minPrecedence, implicitSemicolon);
}

ast::expression* parse_subexpression(parser_state &state, ast::node *parent, int minPrecedence, bool implicitSemicolon);

/// Parses an unary operator.
ast::unary_operator* parse_unary_operator(parser_state &state, ast::node *parent, bool implicitSemicolon)
{
	// Unary operator
	ast::operator_id::t id = unary_operator(next_token(state, implicitSemicolon).token.type);

	if (id == ast::operator_id::none)
		FUNPL_PARSE_TOKEN_ERROR(
				state, debug::error_code::unexpected_token,
				"unexpeced token \"" << lean::from_range<std::string>(state.token.range)
					<< "\" (" << token_type_name(state.token.type)
					<< "), expected unary operator"
			);

	// Unary operator
	accept(state);

	// Operator
	auto operator_ = state.tree->create_node<ast::unary_operator>(parent);
	operator_->id = id;
	
	// Operand
	operator_->operand = parse_subexpression(state, operator_, ast::operator_info(id).precedence + 1, implicitSemicolon);

	return operator_;
}

/// Parses an expression.
ast::expression* parse_primary_expression(parser_state &state, ast::node *parent, int minPrecedence, bool implicitSemicolon)
{
	ast::expression *expr = nullptr;

	switch (next_token(state, implicitSemicolon).token.type)
	{
	// Identifier
	case token_type::tok_identifier:
		expr = parse_identifier(state, parent);
		break;

	// Numeric literal
	case token_type::tok_num_literal:
		expr = parse_num_literal(state, parent);
		break;
	// Character literal
	case token_type::tok_char_literal:
		expr = parse_char_literal(state, parent);
		break;
	// String literal
	case token_type::tok_string_literal:
		expr = parse_string_literal(state, parent);
		break;

	// Sub-expression
	case token_type::tok_oparen:
		{
			// Move to sub-expression
			accept(state);

			// NOTE: No implicit semicolons necessary (closing parentheses!)
			expr = parse_expression(state, parent, false);

			// Make sure full sub-expression has been parsed
			expect_cont(state, token_type::tok_cparen);
			break;
		}

	// Lambda function
	case token_type::kw_fun:
		expr = parse_lambda_function(state, parent, implicitSemicolon);
		break;

	// Sub-compound
	case token_type::tok_obrace:
		expr = parse_compound(state, parent);
		break;
		
	// If statement
	case token_type::kw_if:
		expr = parse_if_statement(state, parent, implicitSemicolon);
		break;

	// Try-catch statement
	case token_type::kw_try:
		expr = parse_try_statement(state, parent, implicitSemicolon);
		break;

	// New expression
	case token_type::kw_new:
		expr = parse_new_expression(state, parent);
		break;
	// Delete expression
	case token_type::kw_delete:
		expr = parse_delete_expression(state, parent, implicitSemicolon);
		break;

	// Guard expression
	case token_type::kw_guard:
		expr = parse_guard_expression(state, parent, implicitSemicolon);
		break;
	// Unguard expression
	case token_type::kw_unguard:
		expr = parse_unguard_expression(state, parent);
		break;

	// Unary operator or error
	default:
		// TODO: Not actually EXPECTING unary operator, improve error message
		expr = parse_unary_operator(state, parent, implicitSemicolon);
	}

	// Any expression may end with postfix operators
	return maybe_parse_postfix_operator(state, parent, LEAN_ASSERT_NOT_NULL(expr), minPrecedence, implicitSemicolon);
}

/// Parses an expression.
ast::expression* maybe_parse_binary_operators(parser_state &state, ast::node *parent, ast::expression *left, int minPrecedence, bool implicitSemicolon)
{
	while (true)
	{
		// Binary operator
		ast::operator_id::t operatorID = binary_operator(next_token(state, implicitSemicolon).token.type);

		if (operatorID == ast::operator_id::none)
			break;

		// Precendence >= minimum precedence
		ast::operator_desc operatorDesc = ast::operator_info(operatorID);

		if (operatorDesc.precedence < minPrecedence)
			break;

		// Evaluate binary operator
		accept(state);

		// Preliminary right subexpression
		ast::expression *right = parse_primary_expression(state, parent, operatorDesc.precedence + 1, implicitSemicolon);

		// Evaluate right operators with higher precendence (or right-associative & same precedence) first
		while (true)
		{
			// Binary operator
			ast::operator_id::t rightID = binary_operator( next_token(state, implicitSemicolon).token.type );

			if (rightID == ast::operator_id::none)
				break;

			// Precedence > current precedence
			ast::operator_desc rightDesc = ast::operator_info(rightID);

			if ((rightDesc.precedence + rightDesc.right_associative) <= operatorDesc.precedence)
				break;

			// Evaluate right operator first
			right = maybe_parse_binary_operators(state, parent, right, rightDesc.precedence, implicitSemicolon);
		}

		// Operator
		auto operator_ = state.tree->create_node<ast::binary_operator>(parent);
		operator_->id = operatorID;

		// Left subexpression
		operator_->left = left;
		left->parent = operator_;
		
		// Right expression
		operator_->right = right;
		right->parent = operator_;

		// Next operator
		left = operator_;
	}

	return left;
}

/// Parses an expression.
ast::expression* parse_subexpression(parser_state &state, ast::node *parent, int minPrecedence, bool implicitSemicolon)
{
	// First sub-expression
	auto expression = parse_primary_expression(state, parent, minPrecedence, implicitSemicolon);

	// Apply subsequent binary operators
	return maybe_parse_binary_operators(state, parent, expression, minPrecedence, implicitSemicolon);
}

/// Parses an expression.
ast::expression* parse_expression(parser_state &state, ast::node *parent, bool implicitSemicolon)
{
	return parse_subexpression(state, parent, 0, implicitSemicolon);
}

/// Parses a type expression.
ast::type_expression* parse_type_expression(parser_state &state, ast::node *parent, bool implicitSemicolon)
{
	auto expr = state.tree->create_node<ast::type_expression>(parent);
	expr->type = parse_type(state, expr, implicitSemicolon);
	return expr;
}

} // namespace

} // namespace